﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using ScreenSharing;
using ScreenSharing.sdk;

namespace SmartConference.SmartPlayer
{
    public delegate void PublishStatusChange(uint code);
    public class PublishManager
    {

        #region dll
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern IntPtr GetForegroundWindow();
        #endregion

        public event RtmpConnected RtmpConnectedEnevt;
        public event RtmpConnectIsOk RtmpConnectIsOkEvent;
        public event PublishStatusChange PublishStatusChange;

        #region delegate

        delegate void ScreenRegionChooseCallback(UInt32 msg_id, NT_PB_RectRegion rectRegion);
        delegate void SetCaptureImageCallBack(UInt32 result, [MarshalAs(UnmanagedType.LPStr)] String file_name);
        delegate void PbSetEventCallBack(UInt32 event_id, Int64 param1, Int64 param2, UInt64 param3, UInt64 param4, [MarshalAs(UnmanagedType.LPStr)] String param5, [MarshalAs(UnmanagedType.LPStr)] String param6, IntPtr param7);
        delegate void SetVideoPreviewImageCallBack(NT_VideoFrame frame);

        public delegate void RtmpConnected();
        public delegate void RtmpConnectIsOk(bool isOk,string info);

    
        #endregion

        #region 事件
        private ScreenRegionChooseCallback set_screen_region_choose_callback_;
        private SetCaptureImageCallBack set_capture_image_call_back_;
      
        /// <summary>
        /// 推送连接状态
        /// </summary>
        private PbSetEventCallBack pb_set_event_call_back_;


        private SetVideoPreviewImageCallBack set_video_preview_image_callback_;

        private NT_PB_SDKEventCallBack pb_event_call_back_;
        #endregion

        public bool IsSdkInit { get; set; }
        public bool IsPublishing { get; set; }

        private IntPtr WinFormHandl { get; }

        private IntPtr PublisherHandle { get; set; }


        public PublishManager()
        {
            pb_set_event_call_back_ = PbEventCallBack;
            UInt32 isInited = NTSmartPublisherSDK.NT_PB_Init(0, IntPtr.Zero);
            IsSdkInit = isInited == 0;
            WinFormHandl = GetForegroundWindow();
        }


        #region Start
        public bool Start(string url)
        {
            try
            {
                End();

                if (PublisherHandle == IntPtr.Zero)
                {
                    if (!OpenPublisherHandle())
                        return false;
                }

                SetCommonOptionToPublisherSdk(PublisherHandle);

                NTSmartPublisherSDK.NT_PB_SetURL(PublisherHandle, url, IntPtr.Zero);

                //设置用户数据发送队列大小
                NTSmartPublisherSDK.NT_PB_SetPostUserDataQueueMaxSize(PublisherHandle, 3, 0);

                if (NTBaseCodeDefine.NT_ERC_OK ==
                    NTSmartPublisherSDK.NT_PB_StartPublisher(PublisherHandle, IntPtr.Zero))
                {
                    IsPublishing = true;
                    return true;
                }
                PublisherHandle = IntPtr.Zero;
            }
            catch (Exception ex)
            {
               Log4netHelper.Error(ex);
            }
            return false;
        }

        public void End()
        {
            try
            {
                NTSmartPublisherSDK.NT_PB_StopPublisher(PublisherHandle);
                NTSmartPublisherSDK.NT_PB_Close(PublisherHandle);
                PublisherHandle = IntPtr.Zero;
                IsPublishing = false;
            }
            catch (Exception ex)
            {
                Log4netHelper.Error(ex);
            }
        }

        private bool OpenPublisherHandle()
        {
            try
            {
                if (PublisherHandle != IntPtr.Zero)
                    return true;

                // 视频
                UInt32 video_option = (UInt32)NTSmartPublisherDefine.NT_PB_E_VIDEO_OPTION.NT_PB_E_VIDEO_OPTION_SCREEN;

                // 音频(扬声器)
                UInt32 audio_option = (UInt32)NTSmartPublisherDefine.NT_PB_E_AUDIO_OPTION.NT_PB_E_AUDIO_OPTION_NO_AUDIO;

                if (NTBaseCodeDefine.NT_ERC_OK != NTSmartPublisherSDK.NT_PB_Open(out var publisherHandle, video_option, audio_option, 0, IntPtr.Zero))
                    return false;
                PublisherHandle = publisherHandle;


                if (PublisherHandle != IntPtr.Zero)
                {
                    pb_event_call_back_ = new NT_PB_SDKEventCallBack(PbSDKEventCallBack);
                    NTSmartPublisherSDK.NT_PB_SetEventCallBack(publisherHandle, WinFormHandl, pb_event_call_back_);
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {

                Log4netHelper.Error(ex);
            }
            return false;
        }

        private void PbSDKEventCallBack(IntPtr handle, IntPtr user_data, UInt32 event_id, Int64 param1, Int64 param2, UInt64 param3, UInt64 param4, [MarshalAs(UnmanagedType.LPStr)] String param5, [MarshalAs(UnmanagedType.LPStr)] String param6, IntPtr param7)
        {
            try
            {
                pb_set_event_call_back_(event_id, param1, param2, param3, param4, param5, param6, param7);
            }
            catch (Exception ex)
            {
                Log4netHelper.Error(ex);
            }
        }

        private void SetCommonOptionToPublisherSdk(IntPtr _publisherHandle)
        {
            try
            {
                //桌面
                NTSmartPublisherSDK.NT_PB_SetScreenClip(_publisherHandle, 0, 0, 0, 0);
                NTSmartPublisherSDK.NT_PB_SetFrameRate(_publisherHandle, 15);

                //采用dxgi采集屏幕
                NTSmartPublisherSDK.NT_PB_EnableDXGIScreenCapturer(_publisherHandle, 1);

                //采集时不停用aero
                NTSmartPublisherSDK.NT_PB_DisableAeroScreenCapturer(_publisherHandle, 0);

                //设置平均码率
                NTSmartPublisherSDK.NT_PB_SetVideoBitRate(_publisherHandle, 2000);

                //视频智能0-20
                NTSmartPublisherSDK.NT_PB_SetVideoQuality(_publisherHandle, 10);

                //最大码率
                NTSmartPublisherSDK.NT_PB_SetVideoMaxBitRate(_publisherHandle, 4000);

                //关键帧间隔
                NTSmartPublisherSDK.NT_PB_SetVideoKeyFrameInterval(_publisherHandle, 45);

                NTSmartPublisherSDK.NT_PB_SetVideoEncoderProfile(_publisherHandle, 1);

                //编码速度
                NTSmartPublisherSDK.NT_PB_SetVideoEncoderSpeed(_publisherHandle, 3);

                NTSmartPublisherSDK.NT_PB_SetVideoCompareSameImage(_publisherHandle, 1, 0);

                NTSmartPublisherSDK.NT_PB_SetVideoMaxKeyFrameInterval(_publisherHandle, 0);

                NTSmartPublisherSDK.NT_PB_SetPublisherAudioCodecType(_publisherHandle, 1);

                //静音
                //NTSmartPublisherSDK.NT_PB_SetMute(_publisherHandle, 1);

                //采集扬声器

                //回音消除 关
                NTSmartPublisherSDK.NT_PB_SetEchoCancellation(_publisherHandle, 0, 0);

                //噪音抑制 1=开 ；0 = 关
                NTSmartPublisherSDK.NT_PB_SetNoiseSuppression(_publisherHandle, 0);

                //自动增益控制关
                NTSmartPublisherSDK.NT_PB_SetAGC(_publisherHandle, 0);

                //端点检测AVD
                NTSmartPublisherSDK.NT_PB_SetVAD(_publisherHandle, 0);
            }
            catch (Exception ex)
            {
                Log4netHelper.Error(ex);
            }
        }

        #endregion

        /// <summary>
        /// 推送连接状态
        /// </summary>
        /// <param name="event_id"></param>
        /// <param name="param1"></param>
        /// <param name="param2"></param>
        /// <param name="param3"></param>
        /// <param name="param4"></param>
        /// <param name="param5"></param>
        /// <param name="param6"></param>
        /// <param name="param7"></param>
        private void PbEventCallBack(uint event_id, long param1, long param2, ulong param3, ulong param4, string param5, string param6, IntPtr param7)
        {
            try
            {
                var event_log = "";
                switch (event_id)
                {
                    case (uint)NTSmartPublisherDefine.NT_PB_E_EVENT_ID.NT_PB_E_EVENT_ID_CONNECTING:
                        if (!String.IsNullOrEmpty(param5))
                            event_log = $"push connecting url:{param5}";
                            RtmpConnectIsOkEvent?.Invoke(false, "连接中");
                        IsPublishing = false;
                        break;

                    case (uint)NTSmartPublisherDefine.NT_PB_E_EVENT_ID.NT_PB_E_EVENT_ID_CONNECTION_FAILED:
                        if (!String.IsNullOrEmpty(param5))
                            event_log = $"push connection failed url:{param5}";
                        RtmpConnectIsOkEvent?.Invoke(false,"连接失败");
                        IsPublishing = false;
                        break;

                    case (uint)NTSmartPublisherDefine.NT_PB_E_EVENT_ID.NT_PB_E_EVENT_ID_CONNECTED:
                        if (!String.IsNullOrEmpty(param5))
                            event_log = $"push connected url:{param5}";
                        RtmpConnectedEnevt?.Invoke();
                        RtmpConnectIsOkEvent?.Invoke(true,"连接成功");
                        IsPublishing = true;
                        break;

                    case (uint)NTSmartPublisherDefine.NT_PB_E_EVENT_ID.NT_PB_E_EVENT_ID_DISCONNECTED:
                        if (!String.IsNullOrEmpty(param5))
                            event_log = $"push disconnected url:{param5}";
                        RtmpConnectIsOkEvent?.Invoke(false, "连接已断开");
                        IsPublishing = false;
                        break;

                    case (uint)NTSmartPublisherDefine.NT_PB_E_EVENT_ID.NT_PB_E_EVENT_ID_RECORDER_START_NEW_FILE:
                        if (!String.IsNullOrEmpty(param5))
                            event_log = $"start new recorder , file name:{param5}";
                        break;

                    case (uint)NTSmartPublisherDefine.NT_PB_E_EVENT_ID.NT_PB_E_EVENT_ID_ONE_RECORDER_FILE_FINISHED:
                        if (!String.IsNullOrEmpty(param5))
                            event_log = $"finish recorder file , file name:{param5}";
                        break;

                    case (uint)NTSmartPublisherDefine.NT_PB_E_EVENT_ID.NT_PB_E_EVENT_ID_CAPTURE_WINDOW_INVALID:
                        event_log = " capture window invalid";
                        Log4netHelper.Info("capture window invalid");
                        break;

                    case (uint)NTSmartPublisherDefine.NT_PB_E_EVENT_ID.NT_PB_E_EVENT_ID_RTSP_URL:
                        event_log = " notify RTSP publisher url..";
                    
                        break;
                    default:
                        break;
                }
                PublishStatusChange?.Invoke(event_id);
                if (string.IsNullOrWhiteSpace(event_log))
                     Log4netHelper.Info(event_log);
            }
            catch (Exception ex)
            {
                Log4netHelper.Error(ex);
            }
        }
    }



    public struct NT_VideoFrame
    {
        public Int32 width_;   // 图像宽
        public Int32 height_;  // 图像高
        public IntPtr plane_;
        public Int32 stride_;
    }
}
